package com.taobao.classloader.spring;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.util.Assert;

import com.taobao.classloader.ApplicationContextCreator;
import com.taobao.classloader.ClassLoaderRouter;
import com.taobao.classloader.ClassLoaderScope;

public class ClassLoaderFactoryBean implements FactoryBean, InitializingBean {
	@SuppressWarnings("unused")
	private static Logger				logger		= LoggerFactory.getLogger(ClassLoaderFactoryBean.class);
	private String						className;
	private String						beanRef;
	private String						scopeName;
	private boolean						singleton	= true;
	private ClassLoaderRouter			classLoaderRouter;
	private ApplicationContextCreator	contextCreator = new AllocateClassLoaderContextCreator();
	private ApplicationContext			context;

	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(classLoaderRouter);
		Assert.notNull(contextCreator);
		// context =
		// contextCreator.createApplicationContext(classLoaderRouter.getClassLoaderScope(scopeName),
		// classLoaderRouter.getClassLoader(scopeName));
	}

	private ApplicationContext getApplicationContext() {
		if (context == null) {
			ClassLoaderScope scope = classLoaderRouter.getClassLoaderScope(scopeName);
			ClassLoader classLoader = classLoaderRouter.getClassLoader(scopeName);
			context = contextCreator.createApplicationContext(scope, classLoader);
			((AbstractApplicationContext)context).refresh();
		}
		return context;
	}

	@Override
	public Object getObject() throws Exception {
		if (className != null && beanRef == null) {
			return classLoaderRouter.newInstance(scopeName, className);
		}
		if (className == null && beanRef != null) {
			return getApplicationContext().getBean(beanRef);
		}
		return null;
	}

	@Override
	public boolean isSingleton() {
		return singleton;
	}

	@Override
	public Class<?> getObjectType() {
		if (className != null && beanRef == null) {
			try {
				return classLoaderRouter.getObjectType(scopeName, className);
			} catch (ClassNotFoundException e) {
				return null;
			}
		}
		if (className == null && beanRef != null) {
			return getApplicationContext().getType(beanRef);
		}
		return null;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public String getScopeName() {
		return scopeName;
	}

	public void setScopeName(String scopeName) {
		this.scopeName = scopeName;
	}

	public ClassLoaderRouter getClassLoaderRouter() {
		return classLoaderRouter;
	}

	public void setClassLoaderRouter(ClassLoaderRouter classLoaderRouter) {
		this.classLoaderRouter = classLoaderRouter;
	}

	public ApplicationContextCreator getContextCreator() {
		return contextCreator;
	}

	public String getBeanRef() {
		return beanRef;
	}

	public void setBeanRef(String beanRef) {
		this.beanRef = beanRef;
	}

	public void setContextCreator(ApplicationContextCreator contextCreator) {
		this.contextCreator = contextCreator;
	}

}